using Engine;
using Engine.Graphics;
using GameEntitySystem;
using SCIENEW;

namespace Game {
    public class TankWidget : CanvasWidget, IDragTargetWidget {
        public BevelledRectangleWidget m_rectangleWidget;

        public FluidWidget m_fluidWidget;

        public ITank m_tank;

        public int m_tankIndex;

        public GameWidget m_gameWidget;

        public DragHostWidget m_dragHostWidget;

        public InventoryDragData m_inventoryDragData;

        public float BevelSize {
            get => m_rectangleWidget.BevelSize;
            set => m_rectangleWidget.BevelSize = value;
        }

        public GameWidget GameWidget {
            get {
                if (m_gameWidget == null) {
                    for (ContainerWidget parentWidget = ParentWidget; parentWidget != null; parentWidget = parentWidget.ParentWidget) {
                        var gameWidget = parentWidget as GameWidget;
                        if (gameWidget != null) {
                            m_gameWidget = gameWidget;
                            break;
                        }
                    }
                }
                return m_gameWidget;
            }
        }

        public DragHostWidget DragHostWidget {
            get {
                if (m_dragHostWidget == null) {
                    m_dragHostWidget = (GameWidget != null) ? GameWidget.Children.Find<DragHostWidget>(throwIfNotFound: false) : null;
                }
                return m_dragHostWidget;
            }
        }

        public TankWidget() {
            Size = new Vector2(72f, 72f);
            m_rectangleWidget = new BevelledRectangleWidget
            {
                BevelSize = -2f,
                DirectionalLight = 0.15f,
                CenterColor = Color.Black
            };
            Children.Add(m_rectangleWidget);
            m_fluidWidget = new FluidWidget {
                Size = this.Size - new Vector2( MathF.Abs(BevelSize), MathF.Abs(BevelSize)) * 2,
                Margin = new Vector2( MathF.Abs(BevelSize), MathF.Abs(BevelSize))
            };
            Children.Add(m_fluidWidget);
        }

        public void AssignTank(ITank tank, int tankIndex) {
            m_tank = tank;
            m_tankIndex = tankIndex;
        }

        public override void Update() {
            base.Update();
            if(m_tank == null || m_tankIndex < 0 || m_tankIndex >= m_tank.TanksCount) return;
            m_fluidWidget.m_fluidValue = m_tank.GetTankValue(m_tankIndex);
            m_fluidWidget.m_relativeVolume = m_tank.GetTankVolume(m_tankIndex) / m_tank.GetTankOriginalCapacity(m_tankIndex);
            m_fluidWidget.Size = Size - new Vector2(MathF.Abs(BevelSize), MathF.Abs(BevelSize)) * 2;
        }

        public override void MeasureOverride(Vector2 parentAvailableSize) {
            IsDrawRequired = m_inventoryDragData != null;
            base.MeasureOverride(parentAvailableSize);
        }

        public override void Draw(DrawContext dc) {
            if (m_tank != null && m_inventoryDragData != null)
            {
                if (m_tank.GetTankOriginalCapacity(m_tankIndex) > 0)
                {
                    float num = 80f * GlobalTransform.Right.Length();
                    var center = Vector2.Transform(ActualSize / 2f, GlobalTransform);
                    FlatBatch2D flatBatch2D = dc.PrimitivesRenderer2D.FlatBatch(100);
                    flatBatch2D.QueueEllipse(center, new Vector2(num), 0f, new Color(0, 0, 0, 96) * GlobalColorTransform, 64);
                    flatBatch2D.QueueEllipse(center, new Vector2(num - 0.5f), 0f, new Color(0, 0, 0, 64) * GlobalColorTransform, 64);
                    flatBatch2D.QueueEllipse(center, new Vector2(num + 0.5f), 0f, new Color(0, 0, 0, 48) * GlobalColorTransform, 64);
                    flatBatch2D.QueueDisc(center, new Vector2(num), 0f, new Color(0, 0, 0, 48) * GlobalColorTransform, 64);
                }
            }
            m_inventoryDragData = null;
        }

        public void DragOver(Widget dragWidget, object data) => m_inventoryDragData = data as InventoryDragData;

        public void DragDrop(Widget dragWidget, object data) {
            var inventoryDragData = data as InventoryDragData;
            if (m_tank != null && inventoryDragData != null)
            {
                HandleDragDrop(inventoryDragData.Inventory, inventoryDragData.SlotIndex, inventoryDragData.DragMode, m_tank, m_tankIndex);
            }
        }

        public bool HandleDragDrop(IInventory sourceInventory, int sourceSlotIndex, DragMode dragMode, ITank targetTank, int targetTankIndex) {
            bool flag = false;
            int slotValue = sourceInventory.GetSlotValue(sourceSlotIndex);
            int tankValue = targetTank.GetTankValue(targetTankIndex);
            int slotCount = sourceInventory.GetSlotCount(sourceSlotIndex);
            float tankVolume = targetTank.GetTankVolume(targetTankIndex);
            float tankCapacity = targetTank.GetTankCapacity(m_tankIndex, tankValue);
            if (dragMode == DragMode.SingleItem) {
                slotCount = MathUtils.Min(slotCount, 1);
            }
            ComponentPlayer? componentPlayer = sourceInventory is Component component ? component.Entity.FindComponent<ComponentPlayer>() : null;

            //添加液体
            foreach (var fluid in FluidsManager.Fluids) {
                if (fluid is IScoopableFluid fillingFluid) {
                    int fillingFluidId = FluidsManager.GetFluidID(fluid);
                    if (fillingFluid.AcquireContainer(fillingFluidId).ContainsValue(slotValue)) {//找到了满桶对应的液体，即填充入液体
                        if (tankVolume > 0 && tankValue != fillingFluidId) break;//槽里装了别的液体
                        slotCount = sourceInventory.RemoveSlotItems(sourceSlotIndex, slotCount);//移除原来的空容器，并且把slotCount设置为实际移除容器的数量
                        float fillingVolume = FluidsManager.GetContainerVolume(slotValue) * slotCount;
                        int emptyContainerID = fillingFluid.AcquireContainer(fillingFluidId)[second: slotValue];
                        targetTank.AddTankFluid(m_tankIndex, fillingFluidId, fillingVolume, out float overflow);
                        if (overflow > 0.5f) AudioManager.PlaySound("Audio/Splashes/Splash1", 1f, 0, 0);//播放溢出音效
                        int lastEmptyContainer = ComponentInventoryBase.AcquireItems(sourceInventory, emptyContainerID, slotCount);//返还空容器
                        if (lastEmptyContainer > 0) componentPlayer?.Project.FindSubsystem<SubsystemPickables>().AddPickable(emptyContainerID, lastEmptyContainer, componentPlayer.ComponentBody.Position, Vector3.Zero, null);
                        flag = true;
                    }
                }
            }

            //抽取液体
            if (!flag) {
                Fluid fluid = FluidsManager.GetFluid(tankValue);
                if (fluid is IScoopableFluid scoopableFluid) {
                    int scoopableFluidID = FluidsManager.GetFluidID(fluid);
                    if (scoopableFluid.AcquireContainer(scoopableFluidID).ContainsKey(slotValue)
                        && FluidsManager.GetContainerVolume(slotValue) <= tankVolume) {
                        //槽里面的液体接受前来装它的空桶，并且有充足的液体可供舀起
                        slotCount = sourceInventory.RemoveSlotItems(sourceSlotIndex, slotCount);//移除原来的满容器，并且把slotCount设置为实际移除容器的数量
                        float scoopedVolume = FluidsManager.GetContainerVolume(slotValue) * slotCount;
                        int fullContainerID = scoopableFluid.AcquireContainer(scoopableFluidID)[first: slotValue];
                        targetTank.RemoveTankFluid(m_tankIndex, scoopedVolume);
                        int lastFullContainer = ComponentInventoryBase.AcquireItems(sourceInventory, fullContainerID, slotCount);
                        if (lastFullContainer > 0) componentPlayer?.Project.FindSubsystem<SubsystemPickables>().AddPickable(fullContainerID, lastFullContainer, componentPlayer.ComponentBody.Position, Vector3.Zero, null);
                        flag = true;
                    }
                }
            }


            /*
            if ((tankVolume == 0 || tankVolume == FluidsManager.GetFluidIndexByContainer(slotValue))
                && tankVolume < tankCapacity) {
                int num2 = MathUtils.Min(slotCapacity - slotCount, num);
                if (num2 > 0) {
                    int count2 = sourceInventory.RemoveSlotItems(sourceSlotIndex, num2);
                    targetInventory.AddSlotItems(targetSlotIndex, slotValue, count2);
                    flag = true;
                }
            }
            else if (!ProcessingOnly
                && targetInventory.GetSlotCapacity(targetSlotIndex, slotValue) >= num
                && sourceInventory.GetSlotCapacity(sourceSlotIndex, slotValue2) >= slotCount
                && sourceInventory.GetSlotCount(sourceSlotIndex) == num) {
                int count3 = targetInventory.RemoveSlotItems(targetSlotIndex, slotCount);
                int count4 = sourceInventory.RemoveSlotItems(sourceSlotIndex, num);
                targetInventory.AddSlotItems(targetSlotIndex, slotValue, count4);
                sourceInventory.AddSlotItems(sourceSlotIndex, slotValue2, count3);
                flag = true;
            }
            */
            if (flag) {
                AudioManager.PlaySound("Audio/UI/ItemMoved", 1f, 0f, 0f);
            }
            return flag;
        }
    }
}